---
--类名: GameScene.lua
--创建日期: 2015-4-29
--创建人: 陈小虎
--功能描述: 游戏场景
--修改内容:
--修改日期:
--修改人:
--修改备注:
--

--local ByteArray = require "quick.cc.utils.ByteArray"

local gameSeverNoticeModel = require("app.login.models.gameSeverNoticeModel")
local GameApp = require("app.GameApp")

local GameApp_getTime = GameApp.getTime
local scheduler_tick = scheduler.tick

local GameScene = class("GameScene",function()
    return cc.Director:getInstance():getRunningScene()
end)


local RemoveCacheInterval = 60 * 5

-- 安全sdk上传数据间隔，s
local SAFE_REPORT_GAP = 5

local Director = cc.Director:getInstance()
local TextureCache = Director:getTextureCache()
local FileUtils = cc.FileUtils:getInstance()

function GameScene:ctor()
    self:setName("GameScene")

    self:enableNodeEvents()

    self._isEnterGame = false

    self:scheduleUpdate( handler(self, GameScene.tick), 1/10)

    self.saveTime = GameApp_getTime(app)
    self.garbageTime = GameApp_getTime(app)
    self.safeReportTime = GameApp_getTime(app)
    self._lastRemoveCacheTime = 0
    self._lastScheduleTime = 0

    -- 是否显示转菊花(给非连接需求使用)
    self._isDisplayIndicator = false
    -- 上一次转菊花标准（不一样才会修改菊花显示）
    self.indicatorDisplayFlag = false

    -- midas 授权失败触发次数
    self._midasPermissionFailTimes = 0
    self._midasPermissionDlg = nil

    self:addListener()
end

function GameScene:addListener()
    -- msdk 全服通告，用走马灯展现
    EM:on("OnReciveNoticeFromMSDK", function(content)
        self:showRollNotice({content})
    end)

    EM:on("OnHotFixSceneVisibility",function(name,params)
        local node = self:getChildByName("HotFixScene")
        if node then
            node:setVisible(params.visible)
        end
    end)
    EM:on("OnHotFixLoadingVisibility",function(name,params)
        local node = self:findChild("HotFixScene/hotfix/Panel")
        if node then
            node:setVisible(params.visible)
        end
    end)

    EM:on("OnFunctionUIChanged",function(name,functionId,mode)
        if mode=="close" then
            self._removeCacheDirty = true
        end
    end)

    -- EM:on("onBattleLostConnection",function()
    --     release_print("onBattleLostConnection")
    --     app.session:disconnect()
    --     app.session:showReconnectDialog()
    --     UIHandler:displayConnecterStateUI(false)
    -- end)

    EM:on("onNetworkWeak",function(event,isWeak,tag)
        release_print("onNetworkWeak",isWeak,tag)

        UIHandler:displayConnecterStateUI(isWeak)

    end)

    app.session:on("shared.ServerMessage",function(msg)
        -- dump(msg, "shared.ServerMessage")
        if msg.content then
            if msg.content == SecretManager.ErrMsg then
                EM:notify(SecretManager.ErrEvent)
                return
            end

            -- auth排队已满，会回调到auth，清理回调
            if msg.content == "ErrExceedWaitingMax" then
                app.session:clearAuthCB()
                app.session:disconnect()
                EM:notify("onEnterQueue")
            end

            -- 匹配错误，主动关闭匹配界面
            if msg.content == "ErrCrossServiceUnavailable" then
                app:sendMsg("PvpModel", "onPvpMatchFail")
            end

            local msgConfig = GD:getMessageConfig(msg.content)
            local msgType = msgConfig and tonumber(msgConfig.type) or 2
            local message = msgConfig and L(msgConfig.msgId) or L(msg.content)
            local imMessage = msgConfig and msgConfig.imMessage or 0

            -- 钻石购买授权失败
            if msg.content == "ErrPayServiceErr" then
                self:onMidasPermissionFail(message)
                return
            end

            -- 关闭连接，重登录游戏
            if msg.content == "ErrServerShutDown" or msg.content == "ErrLoginOtherWhere" then
                self:closeToRelaunchApp(message)
                return
            end

            if msgType == 1 then
                display.pushToast(message)
            else
                local messageBox = display.newMessageBox(message, function()
                    if msg.content == "ErrServerMaintain" then
                        -- 服务器维护中，直接重启
                        app:relaunchApp()
                    elseif msg.content == "ErrExceedWaitingMax" then
                        EM:notify("onFailQueue")
                    end
                end)
                UIHandler:addPopDialog(messageBox)
            end
            if imMessage == 1 then
                app:sendMsg("IMModel", "addSystemMsg", msgConfig.msgId)
            end
        end
    end)

    app.session:on("pb_server.S2C_Kickout",function(msg)
        local hintString = ""
        if msg.reason == "ByOtherClient" then
            hintString = L("repeatlogin")
        else
            local config = GD:getMessageConfig(msg.message)
            hintString = config and L(config.msgId) or L(msg.message)
        end

        release_print("pb_server.S2C_Kickout reason:",msg.reason)

        self:closeToRelaunchApp(hintString)
    end)

    app.session:on("tencent.S2C_SafeRecv",function(msg)
        -- dump(msg, "tencent.S2C_SafeRecv")
        -- local bytes = ByteArray.new()
        -- bytes:writeString(msg.content)
        -- print("SafeSDK.getReportData toString", bytes:toString())

        if SAFE_SHIELD_ENABLE and safeapi then
            safeapi.onRecvData(msg.content)
        end
    end)

    -- 游戏服务器下来的公告
    app.session:on("pb_server.S2C_NoticeList",function(ret)
        -- dump(ret, "S2C_NoticeList")
        gameSeverNoticeModel:parseLoginNoticeData() -- 解析之前缓存的已显示过的公告
        gameSeverNoticeModel:setGameSeverNoticeList( ret )
        if self._isEnterGame then
            self:showLoginedNotice()
            --self:showRollNotice()
        end
    end)

    EM:on(app.session.Event_BlockingChanged,function()
        self:checkNeedDisplayIndicator()
    end)

    EM:on("onDisplayIndicator",function(eventName, isDisplay)
        print("onDisplayIndicator", isDisplay)
        self._isDisplayIndicator = isDisplay
        self:checkNeedDisplayIndicator()
    end)
end

function GameScene:onExit()
    EM:notify("OnGameSceneExit")
    EM:removeAll()

    app.session:off("shared.ServerMessage")
    app.session:off("pb_server.S2C_Kickout")
    app.session:off("tencent.S2C_SafeRecv")
    app.session:off("pb_server.S2C_NoticeList")

    release_print("====>OnGameSceneExit")
end

-- 关闭连接，重登录游戏
-- 1. 服务器关闭
-- 2. 账号已在其他设备登录
-- 3. 被踢出服务器
function GameScene:closeToRelaunchApp(msg)
    app.session:disconnect(function()
        local messageBox = display.newMessageBox(msg, function()
            app:relaunchApp()
        end)
        UIHandler:addPopDialog(messageBox)
    end)
end

function GameScene:onMidasPermissionFail(msg)
    -- 授权失败三次后强制重启授权
    self._midasPermissionFailTimes = self._midasPermissionFailTimes + 1
    app:setMidasPermissionOK(false)
    if self._midasPermissionFailTimes <= 5 then
        self:openMidasPermissionDlg(msg)
    else
        self:openMidasPermissionDlg(L("LoginInvalidErrorTip"), true)
    end
end

function GameScene:openMidasPermissionDlg(msg, isMessage)
    if cc.isAlive(self._midasPermissionDlg) then
        self._midasPermissionDlg:removeFromParent()
        self._midasPermissionDlg = nil
    end

    local function relaunch()
        app.channelAPI:setLastWakeUpPlatform(app.channelAPI:getWGPlatform())
        app.channelAPI:logout(function()
            app:relaunchApp()
        end)
    end

    local dlg
    if isMessage then
       dlg = display.newMessageBox(msg, relaunch)
    else
       dlg = display.newConfirmDialog(msg, relaunch)
    end
    dlg:setConfirmText(L("CommonBtnRelaunch"))
    UIHandler:addPopDialog(dlg)
    self._midasPermissionDlg = dlg
end

function GameScene:tick(dt)
    local app = app
    local curtime = GameApp_getTime(app)
    local session = app.session

    scheduler_tick(curtime)

    if (curtime-self._lastScheduleTime) >= 1 then
        self._lastScheduleTime = curtime

        -- gcloud voice 更新
        if im.isVoiceInit then
            im.poll()
        end

        if DEBUG == 0 then
            -- tapm 网络延时 汇报
            tapm.postNTL(session:getDelayTimeMs())
        end
    end

    if UD.dirty and (curtime-self.saveTime) > 1 then
        UD:save()
        UD.dirty = false
        self.saveTime = curtime
    end

    -- 定时获取安全SDK的始化数据，并原封不动发送到游戏服务器。
    if SAFE_SHIELD_ENABLE and safeapi and safeapi.isLogin and (curtime - self.safeReportTime) > SAFE_REPORT_GAP then
        self.safeReportTime = curtime
        local data = safeapi.getReportData()
        if data then
            -- local bytes = ByteArray.new()
            -- bytes:writeString(data)
            -- print("SafeSDK.getReportData", type(data), #data)
            -- print("SafeSDK.getReportData toString", bytes:toString())

            session:request("tencent.C2S_SafeReport", {type=1, content=data})
        end
    end

    if GARBAGE_ENABLE and (curtime- self.garbageTime) >= GARBAGE_INTERVAL then
        local m = collectgarbage("count")
        collectgarbage("collect")
        local gm = m-collectgarbage("count")
        release_print("===>garbage memory ",gm,"KB")
        self.garbageTime = curtime
    end

    if self._removeCacheDirty and (curtime-self._lastRemoveCacheTime) >= RemoveCacheInterval then
        self:autoRemoveCachedTextures()
        self._removeCacheDirty = false
        self._lastRemoveCacheTime = curtime
    end

    if app.channelAPI then
        app.channelAPI:tick(dt)
    end

    session:tick(dt)

    self:checkNeedDisplayIndicator()

    -- loading过程中不生成头像
    if not app:sendMsg("LoadingController", "isInLoading") and 
        not BattleManager:isBattleBusy() then
        display.updateRenderQueue()
    end

    if debug.profileDirty then
        local ok,lmprof = pcall(require,"lmprof")
        if ok then
            if not lmprof.isRunning() then
                local logFile = FileUtils:getWritablePath().."lmprof.lua"
                lmprof.start(logFile,debug.profileMode)
                print("lmprof started mode:",debug.profileMode,logFile)
            else
                lmprof.stop()
                print("lmprof stoped mode:",debug.profileMode)
            end
        end
        debug.profileDirty = false
    end
end

function GameScene:autoRemoveCachedTextures()
    display.purgeUnUsedArmatureCachedData()
    TextureCache:removeUnusedTextures()
    cc.SpriteFrameCache:getInstance():removeUnusedSpriteFrames()
end

function GameScene:checkNeedDisplayIndicator()
    local session = app.session
    local http = app.http
    local needDisplay = false
    if session and http then
        local isConnecting = (session:isConnecting() or session:isBlocked())
        local isClosing = session:isClosing()
        local isHttpConnecting = http.isConnecting()
        needDisplay = (isConnecting or isHttpConnecting or isClosing)
    end

    needDisplay = needDisplay or self._isDisplayIndicator
    if needDisplay~=self.indicatorDisplayFlag then
        --print("======>isConnecting ",isConnecting,"isClosing",isClosing,"isHttpConnecting",isHttpConnecting," needDisplay",needDisplay)
        UIHandler:showIndicator(needDisplay)
        self.indicatorDisplayFlag = needDisplay
    end
end

-- 进入游戏loading结束
function GameScene:onEnterGame()
    self:showLoginedNotice(true)
    self._isEnterGame = true
end

----------------- notice start ------------------
function GameScene:showNotice(noticeList)
    if cc.isDead(self._noticeView) then
        local view = require("app.login.views.LoginNoticeView").new()
        view:setCloseDelegate(function()
            self._noticeView = nil
            self:loginedNoticeOver()
        end)
        view:setOpenUrlDelegate(function(url)
            app.channelAPI:openURL(url)
        end)
        UIHandler:addPopDialog(view)
        self._noticeView = view

        self._noticeView:setData(noticeList)
    else
        -- 已有界面，在已有界面添加notice
        for i,notice in ipairs(noticeList) do
            self._noticeView:addNotice(notice)
        end
    end
end

-- isFirstEnterGame 是第一次进入游戏
function GameScene:showLoginedNotice(isFirstEnterGame) -- Loading完成被调用
    -- print("showLoginedNotice isFirstEnterGame", isFirstEnterGame)
    if _RelaunchAppAction then
        _RelaunchAppAction = nil
    end

    self:performWithDelay(function()
        local noticeList = {}
        local serverNoticeList = gameSeverNoticeModel:getGameSeverNoticeList() -- 登录之后的游戏服务器公告
        if isFirstEnterGame then
            noticeList = gameSeverNoticeModel:getLoginedNoticeList() -- 登录之后MSDK公告
            noticeList = table.attach(noticeList, serverNoticeList)
        else
            noticeList = serverNoticeList
        end

        if #noticeList > 0 then
            -- 公告弹出通知
            self:showNotice(noticeList)
            EM:notify("OnLoginedNoticePopUp")
        else
            self:loginedNoticeOver()
        end

        self:showRollNotice()
    end, 1)
end

function GameScene:showRollNotice()
    local rollNoticeList = gameSeverNoticeModel:getRollNoticeList()
    if rollNoticeList and #rollNoticeList > 0 then
        app:sendMsg("UIController", "showRollNotice", rollNoticeList)
    end
end

function GameScene:loginedNoticeOver()
    --app:sendMsg("RewardModel", "reqPrivilegeInfoForPayNotice")
    EM:notify("onLoginedNoticeOver")
end

function GameScene:checkPayNoticeOver()
    -- 付费弹窗(特权)
    local rewardModel = app:getInst("RewardModel")
    local payNoticeSubType = rewardModel:popUpPayNoticeActivity()
    if payNoticeSubType and payNoticeSubType == Enums.ActivitySubType.Privilege then
        local flag = rewardModel:checkPopUpTimesBySubType(payNoticeSubType)
        if flag then
            app:sendMsg("RewardController", "openPayNoticeView", payNoticeSubType)
            local allTimes = UD:getValueFromGenericByKey("payNoticeAllTimes"..payNoticeSubType) or 0
            UD:saveGeneric("payNoticeAllTimes"..payNoticeSubType, tonumber(allTimes)+1)
            return
        end
    end
    EM:notify("onLoginedNoticeOver")
end
----------------- notice end ------------------

return GameScene
